/*
 * Copyright (c) 2010-present www.walkerljl.org All Rights Reserved.
 * The software source code all copyright belongs to the author, 
 * without permission shall not be any reproduction and transmission.
 */
package org.walkerljl.commons.mail;

import org.walkerljl.commons.Constants;
import org.walkerljl.commons.util.StringUtils;

import javax.mail.Address;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import java.io.UnsupportedEncodingException;

/**
 * Storage for personal name and email address.
 * Serves as a email address adapter between various formats.
 *
 * @author lijunlin
 */
public class MailAddress {

    public static final MailAddress[] EMPTY_ARRAY = new MailAddress[0];

    private final String email;
    private final String personalName;

    /**
     * Creates new address by specifying email and personal name.
     */
    public MailAddress(String personalName, String email) {
        this.email = email;
        this.personalName = personalName;
    }

    /**
     * Creates new address by specifying one of the following:
     * <ul>
     * <li>"foo@bar.com" - only email address.</li>
     * <li>"Jenny Doe &lt;foo@bar.com&gt;" - first part of the string is personal name,
     * and the other part is email, surrounded with &lt; and &gt;.</li>
     * </ul>
     */
    public MailAddress(String address) {
        address = address.trim();

        if (StringUtils.endsWithChar(address, '>') == false) {
            this.email = address;
            this.personalName = null;
            return;
        }

        int ndx = address.lastIndexOf('<');
        if (ndx == -1) {
            this.email = address;
            this.personalName = null;
            return;
        }

        this.email = address.substring(ndx + 1, address.length() - 1);
        this.personalName = address.substring(0, ndx).trim();
    }

    /**
     * Creates new email address from {@link EmailAddress}.
     */
    public MailAddress(EmailAddress emailAddress) {
        this.personalName = emailAddress.getPersonalName();
        this.email = emailAddress.getLocalPart() + '@' + emailAddress.getDomain();
    }

    /**
     * Creates new email address from <code>InternetAddress</code>.
     */
    public MailAddress(InternetAddress internetAddress) {
        this.personalName = internetAddress.getPersonal();
        this.email = internetAddress.getAddress();
    }

    /**
     * Creates new email address from <code>Address</code>.
     */
    public MailAddress(Address address) {
        this(address.toString());
    }

    // ---------------------------------------------------------------- getters

    /**
     * Converts array of <code>Address</code> to {@link MailAddress}.
     */
    public static MailAddress[] createFrom(Address[] addresses) {
        if (addresses == null) {
            return null;
        }
        if (addresses.length == 0) {
            return null;
        }

        MailAddress[] res = new MailAddress[addresses.length];

        for (int i = 0; i < addresses.length; i++) {
            res[i] = new MailAddress(addresses[i]);
        }

        return res;
    }

    /**
     * Converts array of <code>String</code> to {@link MailAddress}.
     */
    public static MailAddress[] createFrom(String[] addresses) {
        if (addresses == null) {
            return null;
        }
        if (addresses.length == 0) {
            return null;
        }

        MailAddress[] res = new MailAddress[addresses.length];

        for (int i = 0; i < addresses.length; i++) {
            res[i] = new MailAddress(addresses[i]);
        }

        return res;
    }


    // ---------------------------------------------------------------- convert

    /**
     * Converts array of {@link EmailAddress} to {@link MailAddress}.
     */
    public static MailAddress[] createFrom(EmailAddress[] addresses) {
        if (addresses == null) {
            return null;
        }
        if (addresses.length == 0) {
            return null;
        }

        MailAddress[] res = new MailAddress[addresses.length];

        for (int i = 0; i < addresses.length; i++) {
            res[i] = new MailAddress(addresses[i]);
        }

        return res;
    }

    /**
     * Returns email address.
     */
    public String getEmail() {
        return email;
    }

    /**
     * Returns personal name, may be <code>null</code>.
     */
    public String getPersonalName() {
        return personalName;
    }

    // ---------------------------------------------------------------- arrays

    /**
     * Creates new {@link EmailAddress}.
     */
    public EmailAddress toEmailAddress() {
        return new EmailAddress(toString());
    }

    /**
     * Creates new <code>InternetAddress</code> from current data.
     */
    public InternetAddress toInternetAddress() throws AddressException {
        try {
            return new InternetAddress(email, personalName, Constants.DEFAULT_ENCODING);
        } catch (UnsupportedEncodingException ueex) {
            throw new AddressException(ueex.toString());
        }
    }

    /**
     * Returns string representation of this email.
     */
    public String toString() {
        if (this.personalName == null) {
            return this.email;
        }
        return this.personalName + " <" + this.email + '>';
    }

}